import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'config.dart';
import 'model.dart';

typedef ResponseCallback = void Function(dynamic? message);

typedef JSBridgeHandler = void Function(
    dynamic data, ResponseCallback? callback);

// flutter_inappwebview插件的JavaScript Handlers
class InAppWebJSHandlerManager {
// flutter_inappwebview插件
  InAppWebViewController? inAppWebViewController;

  BuildContext? context;

  // 存储的消息messageHandler
  Map<String, dynamic> messageHandlers = {};

  // 存储的回调callback, responseCallback
  Map<String, dynamic> responseCallbacks = {};

  // 开启的消息队列，发送的消息均会存储到该队列中
  List<JSMessage>? startupMessageQueue = [];

  // 消息的标识
  int _uniqueId = 0;

  JSChannelManager() {
    // TODO: implement JSChannelManager
  }

  void updateController({
    required BuildContext context,
    InAppWebViewController? inAppWebViewController,
  }) {
    this.context = context;
    this.inAppWebViewController = inAppWebViewController;
  }

  // 处理消息队列
  void flutterFlushMessageQueue() async {
    // 获取h5发送的列表
    // 处理H5存的消息队列发送的MessageQueue
    String? messageQueueString;
    if (inAppWebViewController != null) {
      messageQueueString = await inAppWebViewController?.evaluateJavascript(
          source: webViewJavascriptFetchQueyCommand());
    }

    print("flutterFlushMessageQueue:${messageQueueString}");
    flushMessageQueue(messageQueueString);
  }

  // 处理来自H5的消息列表
  void flushMessageQueue(String? messageQueueString) {
    if (!(messageQueueString != null && messageQueueString.isNotEmpty)) {
      return;
    }

    dynamic? aFromH5Messages = jsonDecode(messageQueueString);
    if (aFromH5Messages != null && aFromH5Messages is List) {
      for (dynamic aMsgJson in aFromH5Messages) {
        if (aMsgJson is Map<String, dynamic>) {
          JSMessage jsMessage = JSMessage.fromJson(aMsgJson);
          print(
              "flushMessageQueue aFromH5Messages aMsgJson:${aMsgJson} jsMessage:${jsMessage}");

          // 从H5获取或者接收到的消息，如果responseId不为空，则为flutter调用H5方法，H5给flutter的回调
          if (jsMessage.responseId != null &&
              jsMessage.responseId!.isNotEmpty) {
            // 如果responseId不为空，则为flutter调用H5方法，H5给flutter的回调
            ResponseCallback? responseCallback =
                responseCallbacks[jsMessage.responseId];
            if (responseCallback != null) {
              // 处理H5返回给flutter的回调
              responseCallback(jsMessage.responseData);
            }
          } else {
            ResponseCallback? responseCallback;
            // 如果responseId为空时候，则是来自H5发送的flutter的消息
            // 获取H5传过来的标识callbackId
            String? callbackId = jsMessage.callbackId;
            if (callbackId != null && callbackId.isNotEmpty) {
              // 接收到来自H5的消息
              JSMessage aMessage = JSMessage();
              aMessage.copy(aNewMessage: aMessage, aOldMessage: jsMessage);

              responseCallback = (dynamic responseData) {
                // flutter回调给H5
                // 将H5传过来的callbackId作为responseId回调传递给H5
                aMessage.responseId = callbackId;
                aMessage.responseData = responseData;
                _queueMessage(aMessage);
              };
            } else {
              responseCallback = (dynamic responseData) {
                // callbackId为空，不做任何处理
              };
            }

            // 从flutter已经注册Register方法中找出对应的方法
            JSBridgeHandler? jsBridgeHandler =
                messageHandlers[jsMessage.handlerName];
            if (jsBridgeHandler != null) {
              // 在flutter该handlerName的方法已经注册register
              jsBridgeHandler(jsMessage.data, responseCallback);
            } else {
              // 在flutter该handlerName没有注册，则不做任何处理
            }
          }
        }
      }
    }
  }

  // 处理从H5收到的消息
  void _dispatchMessage(JSMessage message) async {
    String messageJSON = jsonEncode(message.toJson());

    messageJSON = messageJSON.replaceAll("\\", "\\\\");
    messageJSON = messageJSON.replaceAll("\"", "\\\"");
    messageJSON = messageJSON.replaceAll("\'", "\\\'");
    messageJSON = messageJSON.replaceAll("\n", "\\n");
    messageJSON = messageJSON.replaceAll("\r", "\\r");
    messageJSON = messageJSON.replaceAll("\f", "\\f");
    messageJSON = messageJSON.replaceAll("\u2028", "\\u2028");
    messageJSON = messageJSON.replaceAll("\u2029", "\\u2029");

    String javascriptCommand =
        webViewJavascriptHandleMessageFromObjCCommand(messageJSON);

    if (inAppWebViewController != null) {
      await inAppWebViewController?.evaluateJavascript(
          source: javascriptCommand);
    }
  }

  // 注入js
  void injectJavascript(String javascript) async {
    if (inAppWebViewController != null) {
      await inAppWebViewController?.evaluateJavascript(source: javascript);
    }
  }

  // 注入js
  void injectJavascriptReady() async {
    if (inAppWebViewController != null) {
      await inAppWebViewController?.evaluateJavascript(
          source: '$kWebviewJsBridgeReady');
    }
  }

  // 注入js
  void injectBridgeJavascript() async {
    if (inAppWebViewController != null) {
      await inAppWebViewController?.evaluateJavascript(
          source: '$kInAppWebViewJavascriptBridge');
    }

    print("injectJavascript");

    // 处理flutter发送的消息队列
    if (startupMessageQueue != null && startupMessageQueue!.isNotEmpty) {
      List<JSMessage> tmpList = startupMessageQueue!;
      startupMessageQueue = null;
      for (JSMessage message in tmpList) {
        _dispatchMessage(message);
      }
    }
  }

  // 向H5发送消息
  void _sendData(String handleName,
      {dynamic? data, ResponseCallback? responseCallback}) {
    String callbackId = "flutter_cb_${++_uniqueId}";

    JSMessage jsMessage = JSMessage();
    jsMessage.callbackId = callbackId;
    jsMessage.handlerName = handleName;
    jsMessage.data = data;

    // 将callbackId存储到responseCallbacks中，callbackId会被H5通过responseId返回
    if (responseCallback != null) {
      responseCallbacks[callbackId] = responseCallback;
    }

    _queueMessage(jsMessage);
  }

  // 将发送给H5的消息存到startupMessageQueue中
  void _queueMessage(JSMessage jsMessage) {
    if (startupMessageQueue != null) {
      startupMessageQueue!.add(jsMessage);
    }

    _dispatchMessage(jsMessage);
  }

  // 注入js的command
  String webViewJavascriptCheckCommand() {
    return "typeof window.AppJSBridge == \'object\';";
  }

  String webViewJavascriptFetchQueyCommand() {
    return "AppJSBridge._fetchQueue();";
  }

  String webViewJavascriptHandleMessageFromObjCCommand(String messageJSON) {
    return "AppJSBridge._handleMessageFromObjC('${messageJSON}');";
  }

  // 判断AppJSBridge
  Future<String?> checkJavascriptBridge() async {
    String? result;
    if (inAppWebViewController != null) {
      bool jsBridge = await inAppWebViewController?.evaluateJavascript(
          source: webViewJavascriptCheckCommand());
      result = (jsBridge ? "true" : "false");
    }
    print("checkJavascriptBridge result:${result}");
    return result;
  }

  /// flutter开放出去的方法，flutter调用H5方法统一使用该callHandler
  /// callHandler
  void callHandler(
      String handleName, dynamic? data, ResponseCallback? responseCallback) {
    if (handleName.isNotEmpty) {
      _sendData(handleName, data: data, responseCallback: responseCallback);
    }
  }

  /// flutter注册方法
  /// flutter注册方法，提供给H5调用
  void registerHandler(String handlerName, JSBridgeHandler jsBridgeHandler) {
    if (handlerName.isNotEmpty) {
      messageHandlers[handlerName] = jsBridgeHandler;
    }
  }

  void addJSBridgeHandlers() {
    if (inAppWebViewController != null) {
      messageHandlers.forEach((handlerName, jsBridgeHandler) {
        inAppWebViewController?.addJavaScriptHandler(
            handlerName: handlerName,
            callback: (List<dynamic> arguments) {
              print(
                  "inAppWebViewController.addJavaScriptHandler arguments:${arguments}");
              flutterFlushMessageQueue();
            });
      });
    }
  }

  // 移除注册的方法
  void removeHandler(String handleName) {
    if (handleName.isNotEmpty) {
      messageHandlers.remove(handleName);
    }
  }

  // 重置，将responseCallbacks、startupMessageQueue重置
  void reset() {
    startupMessageQueue = [];
    responseCallbacks = {};
    _uniqueId = 0;
  }
}
